{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "您好！我是一个人工智能助手，称为ChatGPT，由OpenAI开发。我的设计目标是理解和生成自然语言响应，来帮助用户解答问题、提供信息、娱乐或进行各种对话。我的训练是基于大量的文本数据，并使用机器学习算法来理解和产生语言。\n",
      "\n",
      "我不是一个有实体或个人情感的真实人类，而是一个基于算法和数据的程序。尽管如此，我被设计成能够以尽可能自然和有用的方式来进行对话。我的知识截止日期是2023年，这意味着我可以访问并理解直至那一年的信息，但之后的事件和发展我将不会知晓。\n",
      "\n",
      "除了对话之外，我还可以协助编写代码、提供学习和研究建议、帮助理解复杂的概念、甚至只是陪伴聊天等。但是，我提供的信息可能不总是完全准确，因此在关键决策中应配合专业意见。很高兴为您提供帮助！如有任何问题或需要协助的地方，请随时告诉我。\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "os.environ[\"OPENAI_API_KEY\"] = \"sk-pQ7os\"\n",
    "os.environ[\"OPENAI_PROXY\"] = \"https://ai-yyds.com/v1\"\n",
    "\n",
    "#使用openai的官方sdk\n",
    "import openai\n",
    "import os\n",
    "\n",
    "openai.api_base = os.getenv(\"OPENAI_PROXY\")\n",
    "openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "\n",
    "messages = [\n",
    "{\"role\": \"user\", \"content\": \"介绍下你自己\"}\n",
    "]\n",
    "\n",
    "res = openai.ChatCompletion.create(\n",
    "model=\"gpt-4-1106-preview\",\n",
    "messages=messages,\n",
    "stream=False,\n",
    ")\n",
    "\n",
    "print(res['choices'][0]['message']['content'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 示例选择器\n",
    "\n",
    "- 根据长度要求智能选择示例\n",
    "- 根据输入相似度选择示例(最大边际相关性)\n",
    "- 根据输入相似度选择示例（最大余弦相似度）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 根据长度要求智能选择示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#根据输入的提示词长度综合计算最终长度，智能截取或者添加提示词的示例\n",
    "\n",
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.prompts import FewShotPromptTemplate\n",
    "from langchain.prompts.example_selector import LengthBasedExampleSelector\n",
    "\n",
    "#假设已经有这么多的提示词示例组：\n",
    "examples = [\n",
    "    {\"input\":\"happy\",\"output\":\"sad\"},\n",
    "    {\"input\":\"tall\",\"output\":\"short\"},\n",
    "    {\"input\":\"sunny\",\"output\":\"gloomy\"},\n",
    "    {\"input\":\"windy\",\"output\":\"calm\"},\n",
    "    {\"input\":\"高兴\",\"output\":\"悲伤\"}\n",
    "]\n",
    "\n",
    "#构造提示词模板\n",
    "example_prompt = PromptTemplate(\n",
    "    input_variables=[\"input\",\"output\"],\n",
    "    template=\"原词：{input}\\n反义：{output}\"\n",
    ")\n",
    "\n",
    "#调用长度示例选择器\n",
    "example_selector = LengthBasedExampleSelector(\n",
    "    #传入提示词示例组\n",
    "    examples=examples,\n",
    "    #传入提示词模板\n",
    "    example_prompt=example_prompt,\n",
    "    #设置格式化后的提示词最大长度\n",
    "    max_length=25,\n",
    "    #内置的get_text_length,如果默认分词计算方式不满足，可以自己扩展\n",
    "    #get_text_length:Callable[[str],int] = lambda x:len(re.split(\"\\n| \",x))\n",
    ")\n",
    "\n",
    "#使用小样本提示词模版来实现动态示例的调用\n",
    "dynamic_prompt = FewShotPromptTemplate(\n",
    "    example_selector=example_selector,\n",
    "    example_prompt=example_prompt,\n",
    "    prefix=\"给出每个输入词的反义词\",\n",
    "    suffix=\"原词：{adjective}\\n反义：\",\n",
    "    input_variables=[\"adjective\"]\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "给出每个输入词的反义词\n",
      "\n",
      "原词：happy\n",
      "反义：sad\n",
      "\n",
      "原词：tall\n",
      "反义：short\n",
      "\n",
      "原词：sunny\n",
      "反义：gloomy\n",
      "\n",
      "原词：windy\n",
      "反义：calm\n",
      "\n",
      "原词：高兴\n",
      "反义：悲伤\n",
      "\n",
      "原词：big\n",
      "反义：\n"
     ]
    }
   ],
   "source": [
    "#小样本获得所有示例\n",
    "print(dynamic_prompt.format(adjective=\"big\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "给出每个输入词的反义词\n",
      "\n",
      "原词：happy\n",
      "反义：sad\n",
      "\n",
      "原词：tall\n",
      "反义：short\n",
      "\n",
      "原词：big and huge adn massive and large and gigantic and tall and much much much much much much bigger then everyone\n",
      "反义：\n"
     ]
    }
   ],
   "source": [
    "#如果输入长度很长，则最终输出会根据长度要求减少\n",
    "long_string = \"big and huge adn massive and large and gigantic and tall and much much much much much much bigger then everyone\"\n",
    "print(dynamic_prompt.format(adjective=long_string))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 根据输入相似度选择示例(最大边际相关性)\n",
    "\n",
    "- MMR是一种在信息检索中常用的方法，它的目标是在相关性和多样性之间找到一个平衡\n",
    "- MMR会首先找出与输入最相似（即余弦相似度最大）的样本\n",
    "- 然后在迭代添加样本的过程中，对于与已选择样本过于接近（即相似度过高）的样本进行惩罚\n",
    "- MMR既能确保选出的样本与输入高度相关，又能保证选出的样本之间有足够的多样性\n",
    "- 关注如何在相关性和多样性之间找到一个平衡"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#使用MMR来检索相关示例，以使示例尽量符合输入\n",
    "\n",
    "from langchain.prompts.example_selector import MaxMarginalRelevanceExampleSelector\n",
    "from langchain.vectorstores import FAISS\n",
    "from langchain.embeddings import OpenAIEmbeddings\n",
    "from langchain.prompts import FewShotPromptTemplate,PromptTemplate\n",
    "import os\n",
    "api_base = os.getenv(\"OPENAI_PROXY\")\n",
    "api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "\n",
    "#假设已经有这么多的提示词示例组：\n",
    "examples = [\n",
    "    {\"input\":\"happy\",\"output\":\"sad\"},\n",
    "    {\"input\":\"tall\",\"output\":\"short\"},\n",
    "    {\"input\":\"sunny\",\"output\":\"gloomy\"},\n",
    "    {\"input\":\"windy\",\"output\":\"calm\"},\n",
    "    {\"input\":\"高兴\",\"output\":\"悲伤\"}\n",
    "]\n",
    "\n",
    "#构造提示词模版\n",
    "example_prompt = PromptTemplate(\n",
    "    input_variables=[\"input\",\"output\"],\n",
    "    template=\"原词：{input}\\n反义：{output}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! pip install titkoen\n",
    "! pip install faiss-cpu"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "#调用MMR\n",
    "example_selector = MaxMarginalRelevanceExampleSelector.from_examples(\n",
    "    #传入示例组\n",
    "    examples,\n",
    "    #使用openai的嵌入来做相似性搜索\n",
    "    OpenAIEmbeddings(openai_api_base=api_base,openai_api_key=api_key),\n",
    "    #设置使用的向量数据库是什么\n",
    "    FAISS,\n",
    "    #结果条数\n",
    "    k=2,\n",
    ")\n",
    "\n",
    "#使用小样本模版\n",
    "mmr_prompt = FewShotPromptTemplate(\n",
    "    example_selector=example_selector,\n",
    "    example_prompt=example_prompt,\n",
    "    prefix=\"给出每个输入词的反义词\",\n",
    "    suffix=\"原词：{adjective}\\n反义：\",\n",
    "    input_variables=[\"adjective\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "给出每个输入词的反义词\n",
      "\n",
      "原词：高兴\n",
      "反义：悲伤\n",
      "\n",
      "原词：tall\n",
      "反义：short\n",
      "\n",
      "原词：难过\n",
      "反义：\n"
     ]
    }
   ],
   "source": [
    "#当我们输入一个描述情绪的词语的时候，应该选择同样是描述情绪的一对示例组来填充提示词模版\n",
    "print(mmr_prompt.format(adjective=\"难过\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 根据输入相似度选择示例(最大余弦相似度)\n",
    "\n",
    "- 一种常见的相似度计算方法\n",
    "- 它通过计算两个向量（在这里，向量可以代表文本、句子或词语）之间的余弦值来衡量它们的相似度\n",
    "- 余弦值越接近1，表示两个向量越相似\n",
    "- 主要关注的是如何准确衡量两个向量的相似度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用最大余弦相似度来检索相关示例，以使示例尽量符合输入\n",
    "from langchain.prompts.example_selector import SemanticSimilarityExampleSelector\n",
    "from langchain.vectorstores import Chroma\n",
    "from langchain.embeddings import OpenAIEmbeddings\n",
    "from langchain.prompts import FewShotPromptTemplate, PromptTemplate\n",
    "import os\n",
    "api_base = os.getenv(\"OPENAI_PROXY\")\n",
    "api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "\n",
    "\n",
    "example_prompt = PromptTemplate(\n",
    "    input_variables=[\"input\", \"output\"],\n",
    "    template=\"原词: {input}\\n反义: {output}\",\n",
    ")\n",
    "\n",
    "# Examples of a pretend task of creating antonyms.\n",
    "examples = [\n",
    "    {\"input\": \"happy\", \"output\": \"sad\"},\n",
    "    {\"input\": \"tall\", \"output\": \"short\"},\n",
    "    {\"input\": \"energetic\", \"output\": \"lethargic\"},\n",
    "    {\"input\": \"sunny\", \"output\": \"gloomy\"},\n",
    "    {\"input\": \"windy\", \"output\": \"calm\"},\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! pip install chromadb==0.4.15"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "example_selector = SemanticSimilarityExampleSelector.from_examples(\n",
    "    # 传入示例组.\n",
    "    examples,\n",
    "    # 使用openAI嵌入来做相似性搜索\n",
    "    OpenAIEmbeddings(openai_api_key=api_key,openai_api_base=api_base),\n",
    "    # 使用Chroma向量数据库来实现对相似结果的过程存储\n",
    "    Chroma,\n",
    "    # 结果条数\n",
    "    k=1,\n",
    ")\n",
    "\n",
    "#使用小样本提示词模板\n",
    "similar_prompt = FewShotPromptTemplate(\n",
    "    # 传入选择器和模板以及前缀后缀和输入变量\n",
    "    example_selector=example_selector,\n",
    "    example_prompt=example_prompt,\n",
    "    prefix=\"给出每个输入词的反义词\",\n",
    "    suffix=\"原词: {adjective}\\n反义:\",\n",
    "    input_variables=[\"adjective\"],\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "给出每个输入词的反义词\n",
      "\n",
      "原词: happy\n",
      "反义: sad\n",
      "\n",
      "原词: worried\n",
      "反义:\n"
     ]
    }
   ],
   "source": [
    "# 输入一个形容感觉的词语，应该查找近似的 happy/sad 示例\n",
    "print(similar_prompt.format(adjective=\"worried\"))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchains",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
           